#include <hal/ioapic.h>
#include <hal/acpi/acpi.h>
#include <mm/mmio.h>

#define LOG_TAG "IOAPIC"
#include <log.h>

#define IOAPIC_BASE_PA 0xFEC00000

static volatile uptr ioapic_base;

u8 ioapic_get_irq(u8 old_irq) {
    acpi_ctx_t* ctx = acpi_get_context();
    if (old_irq >= 24) {
        return old_irq;
    }
    intso_t* int_override = ctx->madt.irq_exception[old_irq];
    return int_override ? (u8)int_override->gsi : old_irq;
}

void ioapic_init() {
    ioapic_base = ioremap(IOAPIC_BASE_PA, 1);

    LOGI("IOAPIC ID: 0x%X VER: 0x%X\n", ioapic_read(IOAPIC_REG_ID), ioapic_read(IOAPIC_REG_VER));
}

void ioapic_write(u8 sel, u32 val) {
    *(u32*)(ioapic_base + IOAPIC_IOREGSEL) = sel;
    *(u32*)(ioapic_base + IOAPIC_IOWIN) = val;
}

u32 ioapic_read(u8 sel) {
    *(u32*)(ioapic_base + IOAPIC_IOREGSEL) = sel;
    return *(u32*)(ioapic_base + IOAPIC_IOWIN);
}

void ioapic_redirect(u8 irq, u8 vector, u8 dst_cpu, u32 flags) {
    u8 sel = IOAPIC_IOREDTBL_BASE + irq * 2;
    // low 32 bits
    ioapic_write(sel, (vector | flags) & 0x1FFFF);
    // high 32 bits
    ioapic_write(sel + 1, dst_cpu << 24);
}